/*
   Copyright 2007 Gavin Bong

   See the NOTICE file distributed with this work for additional information
   regarding copyright ownership.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

package com.raverun.scala.eclipser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import ch.epfl.lamp.sdt.core.IScalaCoreConstants;

/**
 * This action must
 * <ul>
 * <li>add container {@code ch.epfl.lamp.sdt.launching.SCALA_CONTAINER}
 * <li>add {@code ch.epfl.lamp.sdt.core.scalanature}
 * <li>add {@code ch.epfl.lamp.sdt.core.scalabuilder}
 * </ul>
 *
 * @author Gavin Bong
 */
public class Scalaify implements IObjectActionDelegate
{
    private static final String CONTAINER_SCALA = "ch.epfl.lamp.sdt.launching.SCALA_CONTAINER";

    private IJavaProject m_currentJavaProject;

    public void setActivePart( IAction action, IWorkbenchPart targetPart )
    {
        // noop
    }

    public void run( IAction action )
    {
        Shell shell = new Shell();
        if( m_currentJavaProject == null )
        {
            MessageDialog.openInformation( shell, ScalaizerPlugin.PLUGIN_ID,
                    "The selected project must have the java nature. Noop." );
            return;
        }

        try
        {
        // add scala container (if it doesn't exists)
            IClasspathEntry[] classpathEntries = m_currentJavaProject.getRawClasspath();
            if( !hasScalaContainer( classpathEntries ) )
            {
                List<IClasspathEntry> listOfNewEntries = new ArrayList<IClasspathEntry>();
                listOfNewEntries.addAll( Arrays.asList( classpathEntries ) );
                listOfNewEntries.add( JavaCore.newContainerEntry( new Path( CONTAINER_SCALA ) ) );

                m_currentJavaProject.setRawClasspath( listOfNewEntries.toArray( new IClasspathEntry[ listOfNewEntries.size() ] ), null );
            }

        // add scala nature
            IProjectDescription description = m_currentJavaProject.getProject().getDescription();

            if( !description.hasNature( IScalaCoreConstants.SCALA_NATURE_ID ) )
            {
                String[] natures = description.getNatureIds();
                String[] newNatures = new String[natures.length + 1];
                System.arraycopy(natures, 0, newNatures, 0, natures.length);
                newNatures[natures.length] = IScalaCoreConstants.SCALA_NATURE_ID;
                description.setNatureIds(newNatures);
            }

        // add scala builder & remove java builder if it exists
            ICommand[] commands = description.getBuildSpec();
            if( !hasScalaBuilderCommand( commands ) )
            {
                ICommand scalaCommand = description.newCommand();
                scalaCommand.setBuilderName( IScalaCoreConstants.SCALA_BUILDER_ID );

/**
 * The rationale for removing the java builder was based on a problem I had
 * with imported bundles from maven projects. I initially suspected that
 * since the imported eclipse project was sharing the same output target
 * directory as the maven module; any mods to the eclipse project would wiped
 * out all compiled scala artifacts. le 5 fév 2008 12h46
 */
//                int index = 0;
//                if( ( index = indexOfJavaBuilderCommand( commands ) ) >= 0 )
//                {
//                    commands[ index ] = scalaCommand;
//                    description.setBuildSpec( commands );
//                }
//                else
//                {
                    ICommand[] newCommands = new ICommand[ commands.length + 1 ];
                    System.arraycopy(commands, 0, newCommands, 0, commands.length);
                    newCommands[ commands.length ] = scalaCommand;
                    description.setBuildSpec( newCommands );
//                }

            }

            m_currentJavaProject.getProject().setDescription(description, null);

            m_currentJavaProject.getProject().refreshLocal( IResource.DEPTH_INFINITE, null );
        }
        catch (CoreException e)
        {
            // TODO add to Console ?
            e.printStackTrace();
        }
    }

    public void selectionChanged( IAction action, ISelection selection )
    {
        m_currentJavaProject = SelectionUtil.findSelectedJavaProject( selection );
    }

    private final boolean hasScalaContainer( IClasspathEntry[] entries )
    {
        if( entries == null || entries.length == 0 )
            return false;

        boolean found = false;

        for( IClasspathEntry entry : entries )
        {
            if( entry.getPath().equals( CONTAINER_SCALA ) &&
                entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER )
            {
                found = true;
                break;
            }
        }
        return found;
    }

    /**
     * @param commands - existing {@code ICommand}s in the a java project
     * @return true iff the {@code IScalaCoreConstants.SCALA_BUILDER_ID} already exists, false otherwise.
     */
    private final boolean hasScalaBuilderCommand( ICommand[] commands )
    {
        if( commands == null || commands.length == 0 )
            return false;

        boolean found = false;

        for( ICommand command : commands )
        {
            if( command.getBuilderName().equals( IScalaCoreConstants.SCALA_BUILDER_ID ) )
            {
                found = true;
                break;
            }
        }

        return found;
    }

    /**
     *
     * @param commands - an array of existing {@code ICommand}s
     * @return if an ICommand that returns {@code JavaCore#BUILDER_ID} exists, then the index of that {@code ICommand} is returned; otherwise-1 is returned.
     */
    public final int indexOfJavaBuilderCommand( ICommand[] commands )
    {
        if( commands == null || commands.length == 0 )
            return -1;

        int index = 0;
        for( ICommand command : commands )
        {
            if( command.getBuilderName().equals( JavaCore.BUILDER_ID ) )
            {
                return index;
            }
            index++;
        }

        return -1;
    }
}
